#include <linux/fs.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/uaccess.h>
#include <linux/io.h>
#include <linux/cdev.h>
#include <linux/gpio.h>
#include <linux/list.h>
#include <linux/slab.h>
#include <linux/i2c.h>
#include <linux/err.h>
#include <linux/kernel.h>
#include <linux/device.h>
#include <linux/delay.h>
#include <linux/platform_device.h>
#include <linux/pinctrl/pinconf-generic.h>
#include <linux/pinctrl/pinmux.h>
#include <linux/pinctrl/pinctrl.h>

struct virt_function_desc {
	const char *name;
	const char * const *group_names;
	int num_group_names;
	u32 mux_val;
	u32 mux_mask;
};

struct virt_group_desc{
	const char *name;
	const unsigned int *pins;
	const unsigned int npins;

};

struct virt_pinctrl {
	struct pinctrl_dev *pctrl;
	u32 pin_mux_reg[2];
	const struct virt_group_desc *groups;
	unsigned int ngroups;
	const struct virt_function_desc *funcs;
	unsigned int nfuncs;
	spinlock_t lock;
	/*当是具体的pinctrl device driver，需要获取寄存器地址，以便对寄存器地址进行配置*/
	void __iomem *reg_base;
};

static const struct pinctrl_pin_desc virt_pins[] = {
	PINCTRL_PIN(0, "VIO0"),
	PINCTRL_PIN(1, "VIO1"),
	PINCTRL_PIN(2, "VIO2"),
	PINCTRL_PIN(3, "VIO3"),
	PINCTRL_PIN(4, "VIO4"),
	PINCTRL_PIN(5, "VIO5"),
	PINCTRL_PIN(6, "VIO6"),
	PINCTRL_PIN(7, "VIO7"),
	PINCTRL_PIN(8, "VIO8"),
	PINCTRL_PIN(9, "VIO9"),
	PINCTRL_PIN(10, "VIO10"),
	PINCTRL_PIN(11, "VIO11"),
	PINCTRL_PIN(12, "VIO12"),
	PINCTRL_PIN(13, "VIO13"),
	PINCTRL_PIN(14, "VIO14"),
	PINCTRL_PIN(15, "VIO15"),
	PINCTRL_PIN(16, "VIO16"),
	PINCTRL_PIN(17, "VIO17"),
	PINCTRL_PIN(18, "VIO18"),
	PINCTRL_PIN(19, "VIO19"),
	PINCTRL_PIN(20, "VIO20"),
	PINCTRL_PIN(21, "VIO21"),
	PINCTRL_PIN(22, "VIO22"),
	PINCTRL_PIN(23, "VIO23"),
	PINCTRL_PIN(24, "VIO24"),
	PINCTRL_PIN(25, "VIO25"),
	PINCTRL_PIN(26, "VIO26"),
	PINCTRL_PIN(27, "VIO27"),
	PINCTRL_PIN(28, "VIO28"),
	PINCTRL_PIN(29, "VIO29"),
	PINCTRL_PIN(30, "VIO30"),
	PINCTRL_PIN(31, "VIO31"),
	#if 0
	PINCTRL_PIN(32, "VIO32"),
	PINCTRL_PIN(33, "VIO33"),
	PINCTRL_PIN(34, "VIO34"),
	PINCTRL_PIN(35, "VIO35"),
	PINCTRL_PIN(36, "VIO36"),
	PINCTRL_PIN(37, "VIO37"),
	PINCTRL_PIN(38, "VIO38"),
	PINCTRL_PIN(39, "VIO39"),
	PINCTRL_PIN(40, "VIO40"),
	PINCTRL_PIN(41, "VIO41"),
	PINCTRL_PIN(42, "VIO42"),
	PINCTRL_PIN(43, "VIO43"),
	PINCTRL_PIN(44, "VIO44"),
	PINCTRL_PIN(45, "VIO45"),
	PINCTRL_PIN(46, "VIO46"),
	PINCTRL_PIN(47, "VIO47"),
	PINCTRL_PIN(48, "VIO48"),
	PINCTRL_PIN(49, "VIO49"),
	PINCTRL_PIN(50, "VIO50"),
	PINCTRL_PIN(51, "VIO51"),
	PINCTRL_PIN(52, "VIO52"),
	PINCTRL_PIN(53, "VIO53"),
	PINCTRL_PIN(54, "VIO54"),
	PINCTRL_PIN(55, "VIO55"),
	PINCTRL_PIN(56, "VIO56"),
	PINCTRL_PIN(57, "VIO57"),
	PINCTRL_PIN(58, "VIO58"),
	PINCTRL_PIN(59, "VIO59"),
	PINCTRL_PIN(60, "VIO60"),
	PINCTRL_PIN(61, "VIO61"),
	PINCTRL_PIN(62, "VIO62"),
	PINCTRL_PIN(63, "VIO63"),
	#endif
};

static const unsigned int iic0_pins[] = {0, 1};
static const unsigned int iic1_pins[] = {4, 5};
static const unsigned int iic2_pins[] = {11, 12};

static const unsigned int uart0_pins[] = {2, 3};
static const unsigned int uart1_pins[] = {4, 5};

static const unsigned int spi0_pins[] = {6, 7, 8, 9};

static const unsigned int can1_pins[] = {10, 13};
static const unsigned int can0_pins[] = {30, 31};
static const unsigned int nand0_pins[] = {14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29};


/*
#define DEFINE_ZYNQ_PINCTRL_GRP(nm) \
	{ \
		.name = #nm "_grp", \
		.pins = nm ## _pins, \
		.npins = ARRAY_SIZE(nm ## _pins), \
	}

static const struct zynq_pctrl_group zynq_pctrl_groups[] = {
	DEFINE_ZYNQ_PINCTRL_GRP(ethernet0_0),
	DEFINE_ZYNQ_PINCTRL_GRP(ethernet1_0),
	DEFINE_ZYNQ_PINCTRL_GRP(mdio0_0),

*/


#define VIRT_PINCTRL_GRP(_name) \
		{ \
			.name = #_name "_group", \
			.pins = _name ## _pins, \
			.npins = ARRAY_SIZE(_name ## _pins), \
		}
static const struct virt_group_desc virt0612_pinctrl_groups[] =
{
	VIRT_PINCTRL_GRP(iic0),
	VIRT_PINCTRL_GRP(iic1),
	VIRT_PINCTRL_GRP(iic2),
	VIRT_PINCTRL_GRP(uart0),
	VIRT_PINCTRL_GRP(uart1),
	VIRT_PINCTRL_GRP(spi0),
	VIRT_PINCTRL_GRP(can0),
	VIRT_PINCTRL_GRP(can1),
	VIRT_PINCTRL_GRP(nand0),
};
	
static const char * const iic0_group[] = {"iic0_group"};
static const char * const iic1_group[] = {"iic1_group"};
static const char * const iic2_group[] = {"iic2_group"};
static const char * const uart0_group[] = {"uart0_group"};
static const char * const uart1_group[] = {"uart1_group"};
static const char * const spi0_group[] = {"spi0_group"};
static const char * const can0_group[] = {"can0_group"};
static const char * const can1_group[] = {"can1_group"};
static const char * const nand0_group[] = {"nand0_group"};
#define VIRT_PINMUX_FUNCTION(_func_name, _mux_val, _mask)\
	{					\
		.name = #_func_name"_func",				\
		.group_names = _func_name##_group,		\
		.num_group_names = ARRAY_SIZE(_func_name##_group),	\
		.mux_val = _mux_val,			\
		.mux_mask = _mask,			\
	}
static const struct virt_function_desc virt0612_pinmux_functions[] = {
	VIRT_PINMUX_FUNCTION(iic0, 1, 0x03),
	VIRT_PINMUX_FUNCTION(iic1, 1, 0x03),
	VIRT_PINMUX_FUNCTION(iic2, 1, 0x03),
	VIRT_PINMUX_FUNCTION(uart0, 2, 0x03),
	VIRT_PINMUX_FUNCTION(uart1, 2, 0x03),
	VIRT_PINMUX_FUNCTION(spi0, 2, 0x03),
	VIRT_PINMUX_FUNCTION(can0, 2, 0x03),
	VIRT_PINMUX_FUNCTION(can1, 2, 0x03),
	VIRT_PINMUX_FUNCTION(nand0, 1, 0x03),
};
static int virt0612_get_groups_count(struct pinctrl_dev *pctldev)
{
	struct virt_pinctrl *pinctrl_ptr = pinctrl_dev_get_drvdata(pctldev);
	printk("%s:%d\n", __FUNCTION__, __LINE__);

	return pinctrl_ptr->ngroups;
}

static const char *virt0612_get_group_name(struct pinctrl_dev *pctldev,unsigned selector)
{
	struct virt_pinctrl *pinctrl_ptr = pinctrl_dev_get_drvdata(pctldev);
	
	printk("%s:%d\n", __FUNCTION__, __LINE__);
	return pinctrl_ptr->groups[selector].name;
}


static int virt0612_get_group_pins(struct pinctrl_dev *pctldev,unsigned selector,
	const unsigned **pins,unsigned *num_pins)
{
	struct virt_pinctrl *pinctrl_ptr = pinctrl_dev_get_drvdata(pctldev);
	printk("%s:%d\n", __FUNCTION__, __LINE__);

	*pins = pinctrl_ptr->groups[selector].pins;
	*num_pins = pinctrl_ptr->groups[selector].npins;

	return 0;
}


static const struct pinctrl_ops virt_pinctrl_ops =
{
	.get_groups_count = virt0612_get_groups_count,
	.get_group_name = virt0612_get_group_name, 
	.get_group_pins =  virt0612_get_group_pins,
	#ifdef CONFIG_OF
	.dt_node_to_map = pinconf_generic_dt_node_to_map_all,
	.dt_free_map = pinctrl_utils_free_map,
	#endif
};

/*
struct pinmux_ops {
	int (*request) (struct pinctrl_dev *pctldev, unsigned offset);
	int (*free) (struct pinctrl_dev *pctldev, unsigned offset);
	int (*get_functions_count) (struct pinctrl_dev *pctldev);
	const char *(*get_function_name) (struct pinctrl_dev *pctldev,
					  unsigned selector);
	int (*get_function_groups) (struct pinctrl_dev *pctldev,
				  unsigned selector,
				  const char * const **groups,
				  unsigned *num_groups);
	int (*set_mux) (struct pinctrl_dev *pctldev, unsigned func_selector,
			unsigned group_selector);
	int (*gpio_request_enable) (struct pinctrl_dev *pctldev,
				    struct pinctrl_gpio_range *range,
				    unsigned offset);
	void (*gpio_disable_free) (struct pinctrl_dev *pctldev,
				   struct pinctrl_gpio_range *range,
				   unsigned offset);
	int (*gpio_set_direction) (struct pinctrl_dev *pctldev,
				   struct pinctrl_gpio_range *range,
				   unsigned offset,
				   bool input);
	bool strict;
};

*/

static const char *virt0612_get_function_name (struct pinctrl_dev *pctldev,
					  unsigned selector)
{
	struct virt_pinctrl *pinctrl_ptr = pinctrl_dev_get_drvdata(pctldev);
	printk("%s:%d funcname=%s\n", __FUNCTION__, __LINE__, pinctrl_ptr->funcs[selector].name);

	return pinctrl_ptr->funcs[selector].name;
}
static int virt0612_get_functions_count (struct pinctrl_dev *pctldev)
{
	struct virt_pinctrl *pinctrl_ptr = pinctrl_dev_get_drvdata(pctldev);
	printk("%s:%d\n", __FUNCTION__, __LINE__);

	return pinctrl_ptr->nfuncs;
}

static int virt0612_get_function_groups (struct pinctrl_dev *pctldev,
				  unsigned selector,
				  const char * const **groups,
				  unsigned *num_groups)
{
	struct virt_pinctrl *pinctrl_ptr = pinctrl_dev_get_drvdata(pctldev);
	const struct virt_function_desc *func_ptr = &pinctrl_ptr->funcs[selector];
	printk("%s:%d\n", __FUNCTION__, __LINE__);

	*groups = func_ptr->group_names;
	*num_groups = func_ptr->num_group_names;

	return 0;
}



static int virt0612_set_mux(struct pinctrl_dev *pctldev, unsigned func_selector,
			unsigned group_selector)
{
	struct virt_pinctrl *pinctrl_ptr = pinctrl_dev_get_drvdata(pctldev);
	const struct virt_function_desc *func_ptr = &pinctrl_ptr->funcs[func_selector];
	const struct virt_group_desc *group_ptr = &pinctrl_ptr->groups[group_selector];
	int offset = 0;
	int pin = 0;
	int i = 0;
	int shift = 0;
	unsigned long flags;


	for(i = 0; i < group_ptr->npins; i++)
	{
		pin = group_ptr->pins[i];
		offset = (pin*2)/32;
		shift = (pin*2)%32;
		spin_lock_irqsave(&pinctrl_ptr->lock, flags);
		pinctrl_ptr->pin_mux_reg[offset] &= ~((func_ptr->mux_mask)<<shift);
		pinctrl_ptr->pin_mux_reg[offset] |= (func_ptr->mux_val)<<shift;
		spin_unlock_irqrestore(&pinctrl_ptr->lock, flags);
	}

	return 0;
}

static int virt0612_gpio_request_enable (struct pinctrl_dev *pctldev,
								struct pinctrl_gpio_range *range,
								unsigned pin)
{
	struct virt_pinctrl *pinctrl_ptr = pinctrl_dev_get_drvdata(pctldev);
	int offset = 0;
	int shift = 0;
	int mux_mask = 0x3;
	int mux_val = 0;
	unsigned long flags;

	printk("%s:%d pin=%d\n", __FUNCTION__, __LINE__, pin);
	
	offset = (pin*2)/32;
	shift = (pin*2)%32;

	spin_lock_irqsave(&pinctrl_ptr->lock, flags);
	pinctrl_ptr->pin_mux_reg[offset] &= ~(mux_mask<<shift);
	pinctrl_ptr->pin_mux_reg[offset] |= mux_val<<shift;
	spin_unlock_irqrestore(&pinctrl_ptr->lock, flags);
	printk("%s:%d: pinctrl_ptr->pin_mux_reg[%d]=x0%x\n", __FUNCTION__, __LINE__, 
		offset, pinctrl_ptr->pin_mux_reg[offset]);


	return 0;
}

static void virt0612_gpio_disable_free(struct pinctrl_dev *pctldev,
	struct pinctrl_gpio_range *range, unsigned offset)
{

	printk("%s:%d\n", __FUNCTION__, __LINE__);
	return;
}
static int virt0612_free(struct pinctrl_dev *pctldev, unsigned offset)
{
	printk("%s:%d\n", __FUNCTION__, __LINE__);

	return 0;

}

static int virt0612_request(struct pinctrl_dev *pctldev, unsigned offset)
{
	printk("%s:%d\n", __FUNCTION__, __LINE__);

	return 0;

}

static const struct pinmux_ops virt_pinmux_ops = 
{
	.get_function_name = virt0612_get_function_name,
	.get_functions_count = virt0612_get_functions_count,
	.get_function_groups = virt0612_get_function_groups,
	.set_mux = virt0612_set_mux,
	.gpio_request_enable = virt0612_gpio_request_enable,
	.gpio_disable_free = virt0612_gpio_disable_free,
	.strict = true,
	.free = virt0612_free,
	.request = virt0612_request,
};

/*
struct pinconf_ops {
#ifdef CONFIG_GENERIC_PINCONF
	bool is_generic;
#endif
	int (*pin_config_get) (struct pinctrl_dev *pctldev,
			       unsigned pin,
			       unsigned long *config);
	int (*pin_config_set) (struct pinctrl_dev *pctldev,
			       unsigned pin,
			       unsigned long *configs,
			       unsigned num_configs);
	int (*pin_config_group_get) (struct pinctrl_dev *pctldev,
				     unsigned selector,
				     unsigned long *config);
	int (*pin_config_group_set) (struct pinctrl_dev *pctldev,
				     unsigned selector,
				     unsigned long *configs,
				     unsigned num_configs);
	void (*pin_config_dbg_show) (struct pinctrl_dev *pctldev,
				     struct seq_file *s,
				     unsigned offset);
	void (*pin_config_group_dbg_show) (struct pinctrl_dev *pctldev,
					   struct seq_file *s,
					   unsigned selector);
	void (*pin_config_config_dbg_show) (struct pinctrl_dev *pctldev,
					    struct seq_file *s,
					    unsigned long config);
};
*/
#if 0
static struct pinconf_ops vrit_pinconf_ops = 
{
	.pin_config_get
};
#endif

/*
struct pinctrl_desc {
	const char *name;
	const struct pinctrl_pin_desc *pins;
	unsigned int npins;
	const struct pinctrl_ops *pctlops;
	const struct pinmux_ops *pmxops;
	const struct pinconf_ops *confops;
	struct module *owner;
#ifdef CONFIG_GENERIC_PINCONF
	unsigned int num_custom_params;
	const struct pinconf_generic_params *custom_params;
	const struct pin_config_item *custom_conf_items;
#endif
};


*/
static struct pinctrl_desc virt0612_desc = {
	.name = "virt0612",
	.pins = virt_pins,
	.npins = ARRAY_SIZE(virt_pins),
	.pctlops = &virt_pinctrl_ops,
	.pmxops = &virt_pinmux_ops,
	.owner = THIS_MODULE,
};


static ssize_t virt_pinmux_reg_show(struct device *dev, struct device_attribute *attr, char *buf)
{
	struct virt_pinctrl *virt_pinctrl_ptr = dev_get_drvdata(dev);


	return	sprintf(buf, "reg0:0x%x reg1:0x%x\n", virt_pinctrl_ptr->pin_mux_reg[0], virt_pinctrl_ptr->pin_mux_reg[1]);
}
static ssize_t virt_pinctrl_name_show(struct device *dev, struct device_attribute *attr, char *buf)
{
//	struct virt_pinctrl *virt_pinctrl_ptr = dev_get_drvdata(dev);

	return	sprintf(buf, "%s\n", dev_name(dev));
}

static DEVICE_ATTR(virt_pinmux_reg, S_IRUSR, virt_pinmux_reg_show, NULL);
static DEVICE_ATTR(virt_pinctrl_name, S_IRUSR, virt_pinctrl_name_show, NULL);


static struct attribute *virt_pinctrl_attrs[] =
{
	&dev_attr_virt_pinmux_reg.attr,
	&dev_attr_virt_pinctrl_name.attr,
	NULL
};
static const struct attribute_group virt_pinctrl_attr_group = 
{
	.attrs = virt_pinctrl_attrs,
};


static int virt_pinctrl_platform_probe(struct platform_device *platform_dev)
{
	int ret = 0;
	struct virt_pinctrl *virt_pinctrl_ptr;
	#if 0
	struct resource *res;
	#endif
	
	virt_pinctrl_ptr = devm_kzalloc(&platform_dev->dev, sizeof(*virt_pinctrl_ptr), GFP_KERNEL);
	if (!virt_pinctrl_ptr)
		return -ENOMEM;

	#if 0
	res = platform_get_resource(platform_dev, IORESOURCE_MEM, 0);
	virt_pinctrl_ptr->reg_base = devm_ioremap_resource(&platform_dev->dev, res);
	if (IS_ERR(pctrl->base))
		return PTR_ERR(pctrl->base);
	#endif

	
	virt_pinctrl_ptr->groups = virt0612_pinctrl_groups;
	virt_pinctrl_ptr->ngroups = ARRAY_SIZE(virt0612_pinctrl_groups);
	virt_pinctrl_ptr->funcs = virt0612_pinmux_functions;
	virt_pinctrl_ptr->nfuncs = ARRAY_SIZE(virt0612_pinmux_functions);
	spin_lock_init(&virt_pinctrl_ptr->lock);

	printk("%s:%d\n", __FUNCTION__, __LINE__);
	virt_pinctrl_ptr->pctrl = pinctrl_register(&virt0612_desc, &platform_dev->dev, virt_pinctrl_ptr);
	if (IS_ERR(virt_pinctrl_ptr->pctrl))
	{
		pr_err("could not register virt0612 pin driver\n");
		return ret;
	}

	printk("%s:%d %s %s\n", __FUNCTION__, __LINE__, pinctrl_dev_get_name(virt_pinctrl_ptr->pctrl), pinctrl_dev_get_devname(virt_pinctrl_ptr->pctrl));

	sysfs_create_group(&platform_dev->dev.kobj, &virt_pinctrl_attr_group);
	platform_set_drvdata(platform_dev, virt_pinctrl_ptr);
	return 0;
}


static int virt_pinctrl_platform_remove(struct platform_device *platform_dev)
{
	struct virt_pinctrl *virt_pinctrl_ptr = platform_get_drvdata(platform_dev);
	printk("%s:%d\n", __FUNCTION__, __LINE__);

	pinctrl_unregister(virt_pinctrl_ptr->pctrl);
	sysfs_remove_group(&platform_dev->dev.kobj, &virt_pinctrl_attr_group);
	printk("%s:%d\n", __FUNCTION__, __LINE__);
	return 0;
}

static struct platform_driver virt_pinctrl_platform_driver = {
    .driver = {
        .name = "virt_pinctrl_dev",
        .owner = THIS_MODULE,
    },
    .probe = virt_pinctrl_platform_probe,
    .remove = virt_pinctrl_platform_remove,
};


static int __init virt_pinctrl_init(void)
{
	int ret = 0;

	ret = platform_driver_register(&virt_pinctrl_platform_driver);

	return ret;
}

static void __exit virt_pinctrl_exit(void)
{
    printk("%s:%d\n", __FUNCTION__, __LINE__);

    platform_driver_unregister(&virt_pinctrl_platform_driver);
}



module_init(virt_pinctrl_init);
module_exit(virt_pinctrl_exit);
MODULE_DESCRIPTION("Virtual Pinctrl Controller Platform Device Drivers");
MODULE_LICENSE("GPL");
MODULE_AUTHOR("jerry_chg");

